﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Globalization;
using HtmlAgilityPack;

namespace OlapProject
{
    class ImlixParser : IParser
    {
        private int currentPageNumber = 1;
        private int lastPageNumber;

        private const String pageName = "imlix";

        private List<PropertyVO> properties;
        private Dictionary<String, String> types;

        private HtmlWeb htmlWeb;
        private String currentPage;
        private HtmlDocument document;
        private HtmlNode someNode;

        public ImlixParser()
        {
            htmlWeb = new HtmlWeb();
            properties = new List<PropertyVO>();
            prepareTypes();
        }

        private void init()
        {

            properties.Clear();
          
            currentPage = "http://eu.imlix.com/search/for.sale"; // Start page.
            document = htmlWeb.Load(currentPage);
        }

        public List<PropertyVO> getData()
        {
            Log.writeLine("Imlix STARTING ...");
            init();
            getNumberOfAllPages();
            parseAllPages();

            return properties;
        }

        public void prepareTypes()
        {
            types = new Dictionary<string, string>()
            {
                // Key => Value
                {"apartment", "apartment"},
                {"singlefamily", "house"},
                {"multifamily", "house"},
                {"land", "land"},
                {"surgery", "office"},
                {"industrial", "industrial"},
                {"retail", "commercial"},
                {"hotel", "hotel"},
                {"commercial", "land"},
                {"forestry", "other"},
                {"parking", "garage-parking"},
                {"residential", "house"}
            };
        }

        public void getNumberOfAllPages()
        {
            HtmlNode listNode = document.GetElementbyId("search_results_list");
            HtmlNodeCollection paginationLinks = listNode.SelectNodes("//div[@class='pagination_footer pagination']//a");
            HtmlNode lastLink = paginationLinks.Last();
            String lastValue = lastLink.Attributes["href"].Value.ToString();
            HtmlDocument documentLastPage = htmlWeb.Load(lastValue);
            listNode = documentLastPage.GetElementbyId("search_results_list");
            HtmlNodeCollection lastPaginationLinks = listNode.SelectNodes("//div[@class='pagination_footer pagination']//a");
            int.TryParse(lastPaginationLinks.Last().InnerText.ToString(), out lastPageNumber);

            checkDebugMode();
        }

        private void checkDebugMode()
        {
            if (DebugModel.debugMode && (lastPageNumber > DebugModel.MAX_PAGE_IN_DEBUG))
            {
                lastPageNumber = DebugModel.MAX_PAGE_IN_DEBUG;
            }
        }

        public void parseAllPages()
        {   
            do{

                Log.parserLog(currentPageNumber, "Imlix");
                // Get current node with links.
                someNode = document.GetElementbyId("search_results_list");

                // Load next page.
                if(currentPageNumber > 1 && someNode != null)
                {
                    HtmlNodeCollection paginationLinks = someNode.SelectNodes("//div[@class='pagination_footer pagination']//a");

                    foreach (HtmlNode link in paginationLinks)
                        if (link.InnerText.ToString() == currentPageNumber.ToString())
                        {
                            currentPage = link.Attributes["href"].Value.ToString();
                            continue;
                        }

                    // Set next page with links.
                    document = htmlWeb.Load(currentPage);
                    someNode = document.GetElementbyId("search_results_list");
                }

                // Parse details per page.
                if (someNode != null)
                {
                    HtmlNodeCollection allLinksPerPage = someNode.SelectNodes("//div[@class='listing_item_header']/div[@class='listing_item_title']/a[starts-with(@href, 'http://')]");
                    
                    if (allLinksPerPage == null) Console.WriteLine("NULL");
                    else
                    {
                        foreach (HtmlNode link in allLinksPerPage)
                        {
                            HtmlDocument detailsDocument = htmlWeb.Load(link.Attributes["href"].Value.ToString());

                            PropertyVO property = new PropertyVO();
                            property.source = pageName;
                            property.datetime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");

                            // Address.
                            someNode = detailsDocument.DocumentNode.SelectSingleNode("//div[@class='listing_details_header']//h2//span[last()]");
                            if (someNode != null)
                                addAddress(property, someNode.InnerText);

                            // Price.
                            someNode = detailsDocument.DocumentNode.SelectSingleNode("//div[@class='listing_details_header']/span");
                            if (someNode != null)
                                addPrice(property, someNode.InnerText);

                            // Type.
                            someNode = detailsDocument.DocumentNode.SelectSingleNode("//table[@class='overview_table']//td[1]");
                            if (someNode != null)
                                addType(property, someNode.InnerText);

                            // Live Square.
                            someNode = detailsDocument.DocumentNode.SelectSingleNode("//table[@class='overview_table']//tr[1]//td[2]");
                            if (someNode != null)
                                addLiveArea(property, someNode.InnerText);

                            // Land Square.
                            someNode = detailsDocument.DocumentNode.SelectSingleNode("//table[@class='overview_table']//tr[2]//td[2]");
                            if (someNode != null)
                                addLandArea(property, someNode.InnerText);

                            // Bedrooms.
                            someNode = detailsDocument.DocumentNode.SelectSingleNode("//table[@class='overview_table']//tr[6]//td[1]");
                            if (someNode != null)
                                addBedrooms(property, someNode.InnerText);

                            // Bathrooms.
                            someNode = detailsDocument.DocumentNode.SelectSingleNode("//table[@class='overview_table']//tr[7]//td[1]");
                            if (someNode != null)
                                addBathrooms(property, someNode.InnerText);

                            // Add property to list.
                            properties.Add(property);
                        }
                    }
                }

                currentPageNumber++;

            } while (currentPageNumber <= lastPageNumber);

        } // End parse method.

        public void addAddress(PropertyVO property, String parsedAddress)
        {
            if (String.IsNullOrEmpty(parsedAddress))
                return;

            parsedAddress = parsedAddress.Trim();
            String[] partsOfAddress = parsedAddress.Split('/');
            int counter = partsOfAddress.Count();
            if (counter >= 2)
                property.country = partsOfAddress[1].Trim().ToLower();
            if (counter >= 3)
                property.district = partsOfAddress[2].Trim().ToLower();
            if (counter == 4)
                property.city = partsOfAddress[3].Trim().ToLower();
        }

        public void addPrice(PropertyVO property, String price)
        {
            if (String.IsNullOrEmpty(price))
                return;
            else
            {
                String convertedPrice = price.Split(' ')[1].Replace(".", "").Replace(",","").Trim().ToLower();
                property.price = Decimal.Parse(convertedPrice, CultureInfo.InvariantCulture);
            }
        }

        public void addType(PropertyVO property, String type)
        {
            if (String.IsNullOrEmpty(type))
            {
                property.type = "unspecified";
                return;
            }

            type = type.Split('/').Last().Trim().Split(' ').First().Replace("-", "").Trim().ToLower();
            if (types.ContainsKey(type))
                property.type = types[type];
            else
                property.type = "other";
        }

        public void addLiveArea(PropertyVO property, String area)
        {
            if (String.IsNullOrEmpty(area) || area.Contains("-"))
                return;
            else
            {
                String convertedArea = area.Split(' ')[0].Split(',')[0].Replace(".", "").Trim().ToLower();
                property.area = Decimal.Parse(convertedArea, CultureInfo.InvariantCulture);
            }
        }

        public void addLandArea(PropertyVO property, String area)
        {
            if (String.IsNullOrEmpty(area) || area.Contains("-"))
                return;
            else
            {
                String convertedArea = area.Split(' ')[0].Split(',')[0].Replace(".","").Trim().ToLower();
                property.plotArea = Decimal.Parse(convertedArea, CultureInfo.InvariantCulture);
            }
        }

        public void addBedrooms(PropertyVO property, String bedrooms)
        {
            if (String.IsNullOrEmpty(bedrooms) || bedrooms.Contains("-"))
                return;
            else
                property.bedrooms = Int16.Parse(bedrooms.Trim());
        }


        public void addBathrooms(PropertyVO property, String bathrooms)
        {
            if (String.IsNullOrEmpty(bathrooms) || bathrooms.Contains("-"))
                return;
            else
                property.bathrooms = Int16.Parse(bathrooms.Trim());
        }

    } // End class.
}
